﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Lister;
using COFE.Core.Utils;
using System.Text.RegularExpressions;
using COFE.Web;
using COFE.Core;
using COFE.Core.Profile;
using System.IO;
using System.Security;
using System.Net;

namespace COFE.IO.COFEWS
{
    public class COFEWSDirectoryLister : PrimaryDirectoryListerBase
    {
        #region Constructor

        static string uriLogin = "{0}/users/signin";
        static string strUserAndPass = "username={0}&password={1}";
        static string uriLookupEntry = "{0}/lookup?path={1}";
        static string uriListPath = "{0}/lookup?path={1}&rel=list";

        public COFEWSDirectoryLister(IFactory<IDirectoryLister> factory,
         string listerKey,
         string host = @"http://localhost:62863",
         string path = @"",  //WS Path e.g. {TEMP}/a
         string userName = "Test", string password = "Test")
            : this(factory, listerKey, 
            String.Format(uriListPath, host, path),
            userName, password)                        
        {

            _host = host;
            _path = path;

            //_getRootDirectory = () =>
            //   (from e in listPath(path).Entries                 
            //     select COFEShared.EntryConstructor.CreateDirectory(this.ListerKey,
            //         new COFEWSPropertyProvider(this, e))).ToArray();


            _getParent = (e) =>
            {
                string parentPath = 
                    COFEWSPath.GetDirectoryName(
                    e.InternalProperties.GetProperty(
                    COFEWSProperties.EntryPath).ValueAsString);
                Entry parentEntry = this.getEntryPath(parentPath);

                return COFEShared.EntryConstructor.CreateDirectory(this.ListerKey,
                     new COFEWSPropertyProvider(this, parentEntry));
            };
        }


        public COFEWSDirectoryLister(IFactory<IDirectoryLister> factory,
          string listerKey, 
          string rootUri = @"http://localhost:62863/lookup?path=&rel=list",

          string userName = "Test", string password = "Test")
            : base(factory, listerKey)
        {
            Status = DirectoryListerStatusMode.Online;

            var match = Regex.Match(rootUri, RegexPatterns.ParseNetPathPattern);
            _rootUri = rootUri;
            _userName = userName;
            _password = password; 
            
            _host = match.Groups["host"].Value;
            _relativeRootUri = rootUri.Replace(_host, "");
            _rootAddress = rootUri;

            _getParent = (e) =>
                {
                    return COFEShared.CurrentUserProfile.TryParsePath(
                        COFEPath.GetDirectoryName(e.ParseName), 
                        EntryConstructionFlags.LookupIfParseFailed |
                        EntryConstructionFlags.EnableCache) as IInternalDirectoryInfoExA;
                };

            _getRootDirectory = () =>
                new IDirectoryInfo[] { getRootDirectory() };

            _parse = (path, flags) =>
                {                    
                    if (path == "")
                        return getRootDirectory();
                    return null;  
                };
        }

        #endregion

        #region Methods
       


        public override IEnumerable<IFileSystemInfo> List(
            IInternalDirectoryInfoExA parent, EntryConstructionFlags flags)
        {            
            if (!parent.IsPropertySupported(COFEWSProperties.ListUri))
                throw new NotSupportedException();

            string listUri = parent.GetProperty(COFEWSProperties.ListUri).ValueAsString;
            var entryList = list(listUri);
            foreach (var entry in entryList.Entries)
            {
                yield return COFEShared.EntryConstructor.CreateEntry(
                    new COFEWSPropertyProvider(this, entry), flags);
            }

        }

        

        WebResponse sendRequest(string uri, string method, Stream sendStream = null)
        {
            try
            {
                return COFEWSShared.NetClient.SendRequest(uri, method, sendStream);
            }
            catch (WebException ex)
            {
                login();
                return COFEWSShared.NetClient.SendRequest(uri, method, sendStream);
            }
        }

        internal Entry getEntry(string relativeUri)
        {
            string uri = _host + relativeUri;
            var resp = sendRequest(uri, "GET");
            return XmlStreamUtils.EntryFromXmlStream(_rootUri,
                    resp.GetResponseStream());
        }

        void login()
        {
            Console.WriteLine("Login");
            try
            {
                Status = DirectoryListerStatusMode.Online;
                string uri = String.Format(uriLogin, _host);

                var ms = StringUtils.StringToStream(
                    String.Format(strUserAndPass, _userName, _password));
                var response = COFEWSShared.NetClient.SendRequest(uri, "POST", ms);

                Status = DirectoryListerStatusMode.Online;
            }
            catch (Exception ex)
            {
                Status = DirectoryListerStatusMode.Offline;
                throw new SecurityException("Login failed.");
            }
            //Console.WriteLine(response.StatusCode);
        }

        Entry getEntryPath(string wsPath)
        {
            return getEntry(String.Format(uriLookupEntry, "", wsPath));
        }

        Web.IEntryList listPath(string wsPath)
        {
            return list(String.Format(uriListPath, "", wsPath));
        }

        Web.IEntryList list(string relativeUri)
        {
            string uri = _host + relativeUri;
            var resp = sendRequest(uri, "GET");
            return XmlStreamUtils.EntryListFromXmlStream(_host,
                    resp.GetResponseStream());
        }

        Web.IEntryList list(Entry parentEntry)
        {
            var listLink = parentEntry.GetLinks().FirstOrDefault((l) => l.Relation == RelationType.List);
            if (listLink == null)
                throw new NotSupportedException(parentEntry.Name + " do not support list.");
            return list(listLink.Uri);            
        }

        IDirectoryInfo getRootDirectory()
        {
            return COFEShared.EntryConstructor.CreateDirectory(ListerKey,
                     new COFEWSRootPropertyProvider(this, ListerKey, _relativeRootUri), 
                     EntryConstructionFlags.DefaultWithoutCache);
        }

        public override IStreamProvider CreateStreamProvider()
        {
            return new COFEWSStreamProvider(this, _host);
        }

        public override IDirectoryController CreateController()
        {
            return new COFEWSDirectoryController(this);
        }

        
        #endregion

        #region Data

        internal string _host, _path = null, _rootUri;
        internal string _userName, _password;
        private string _rootAddress, _relativeRootUri;
        private IDirectoryInfo _rootDirectory;

        #endregion

        #region Public Properties

        #endregion

    }
}
